﻿using System;
using System.Diagnostics;
using System.Windows;
using System.Windows.Threading;
using FarseerGames.FarseerPhysics.Mathematics;
using FreeGoo.GameEngine;
using FreeGoo.GameEngine.Renderables.Links;
using FreeGoo.GameEngine.Renderables.Particles;
using FreeGoo.LevelClasses;
using FreeGoo.WpfRenderer;

namespace FreeGoo.WpfDemo
{
    public partial class GameWindow
    {
        private const float ParticleHeight = 0;
        private readonly Stopwatch _frameCounterStopWatch = new Stopwatch();
        private DispatcherTimer _frameCounterTimer;
 
        public GameWindow()
        {
            InitializeComponent();
        }

        public Engine Engine { get { return GameControl.Engine; } }

        public GameWindow(CampaignHandler handler, Level level)
        {
            InitializeComponent();
            GameControl.SetHandlerAndLevel(handler, level);
        }

        private void Window_Loaded(object sender, RoutedEventArgs e)
        {
            _frameCounterTimer = new DispatcherTimer();
            _frameCounterTimer.Interval = new TimeSpan(0, 0, 0, 1, 0);
            _frameCounterTimer.Tick += FrameCounterTimerTick;
            _frameCounterTimer.Start();
            _frameCounterStopWatch.Start(); 
            
            try
            {
                if (GameControl.Level == null)
                {
                    GameControl.Level = new Level(new Campaign(new CampaignHandler(GameControl.Engine)), @"..\..\Levels\DemoLevel5.xml");
                }
            }
            catch (Exception ex)
            {
                TrackLevelCheckBox.IsChecked = false;
                MessageBox.Show(ex.Message);
            }
        }

        private void ClearParticles_Click(object sender, RoutedEventArgs e)
        {
            foreach (Particle particle in Engine.Particles)
            {
                particle.ScheduledForDelete = true;
            }
        }

        private void ClearLinks_Click(object sender, RoutedEventArgs e)
        {
            foreach (Link link in Engine.Links)
            {
                link.ScheduledForDelete = true;
            }
        }

        private void CreateBallon_Click(object sender, RoutedEventArgs e)
        {
            ParticleFactory.CreateBalloonParticle(Engine, new Vector2(150, ParticleHeight), ParticleFactory.DefaultBalloonParticleRadius);
        }

        private void CreateChain_Click(object sender, RoutedEventArgs e)
        {
            ParticleFactory.CreateChainParticle(Engine, new Vector2(150, ParticleHeight), ParticleFactory.DefaultChainParticleRadius);
        }

        private void HideLinks_Click(object sender, RoutedEventArgs e)
        {
            foreach (Link link in Engine.Links)
            {
                link.Renderer.Delete();
            }
        }

        private void HideParticles_Click(object sender, RoutedEventArgs e)
        {
            foreach (Particle particle in Engine.Particles)
            {
                particle.Renderer.Delete();
            }
        }

        private void CreateHook_Click(object sender, RoutedEventArgs e)
        {
            ParticleFactory.CreateFixedHookParticle(
                Engine,
                new Vector2(190, ParticleHeight - 50),
                8);
        }

        private void ReloadLevelButton_Click(object sender, RoutedEventArgs e)
        {
            Engine.LoadLevel();
        }

        private void CheckIfLevelIsOutdated(bool force)
        {
            try
            {
                if (TrackLevelCheckBox.IsChecked == true || force)
                {
                    Level level = (Level)Engine.CurrentLevel;
                    if (level.LevelFileChangedOnDisk)
                    {
                        level = new Level(new Campaign(new CampaignHandler(Engine)), level.FileName);
                        Engine.CurrentLevel = level;
                    }
                }
            }
            catch (Exception e)
            {
                TrackLevelCheckBox.IsChecked = false;
                MessageBox.Show(e.Message);
            }
        }

        private void FixParticles_Click(object sender, RoutedEventArgs e)
        {
            foreach (Particle particle in Engine.Particles)
            {
                particle.Body.IsStatic = true;
            }
        }

        private void SetStiffness_Click(object sender, RoutedEventArgs e)
        {
            MixedFactory.PinJointSoftness = float.Parse(StiffnessTextBox.Text) / 100 * MixedFactory.DefaultPinJointSoftness;
            foreach (Link link in Engine.Links)
            {
                link.Joint.Softness = MixedFactory.PinJointSoftness;
            }
        }

        private void CreateGrid_Click(object sender, RoutedEventArgs e)
        {
            int countX = 8;
            int countY = 13;
            int distanceX = 40;
            int distanceY = 50;
            Particle[,] particles = new Particle[countX, countY];
            for (int x = 0; x < countX; x++)
            {
                for (int y = 0; y < countY; y++)
                {
                    particles[x, y] = ParticleFactory.CreateMultiLinkParticle(
                        Engine,
                        new Vector2(50 + x * distanceX, -50 + y * distanceY),
                        8);
                }
            }

            for (int x = 0; x < countX; x++)
            {
                for (int y = 0; y < countY; y++)
                {
                    if (x < countX - 1)
                    {
                        MixedFactory.CreatePinJointLinkBetweenLinkableObjects(Engine, particles[x, y], particles[x + 1, y], particles[x, y]);
                    }

                    if (y < countY - 1)
                    {
                        MixedFactory.CreatePinJointLinkBetweenLinkableObjects(Engine, particles[x, y], particles[x, y + 1], particles[x, y]);
                    }

                    if (x < countX - 1 && y < countY - 1)
                    {
                        MixedFactory.CreatePinJointLinkBetweenLinkableObjects(Engine, particles[x + 1, y], particles[x, y + 1], particles[x + 1, y]);
                        MixedFactory.CreatePinJointLinkBetweenLinkableObjects(Engine, particles[x, y], particles[x + 1, y + 1], particles[x, y]);
                    }
                }
            }
        }

        private void FrameCounterTimerTick(object sender, EventArgs e)
        {
            double time = _frameCounterStopWatch.Elapsed.TotalSeconds;

            if (time > 0)
            {
                Title = String.Format(
                    "RenderFrames/s: {0:f}, PhysFrames/s: {1:f}, PhysicsTime: {2:f}, RenderTime: {3:f}, Mouse=({7:f}, {8:f}), Objects: {4}, Particles: {5}, Links: {6}",
                    Engine.RenderFrameCount / time,
                    Engine.PhysicsFrameCount / time,
                    Engine.PhysicsTime,
                    Engine.RenderTime,
                    Engine.Renderables.Count,
                    Engine.Particles.Count,
                    Engine.Links.Count,
                    CrossMouse.GetPosition(this).X,
                    CrossMouse.GetPosition(this).Y);
            }

            Engine.ResetStatistics();
            _frameCounterStopWatch.Reset();
            _frameCounterStopWatch.Start();

            CheckIfLevelIsOutdated(false);
        }

        private void Window_Closing(object sender, System.ComponentModel.CancelEventArgs e)
        {
            _frameCounterTimer.Stop();
        }
    }
}
